home *** CD-ROM | disk | FTP | other *** search
/ The Atari Compendium / The Atari Compendium (Toad Computers) (1994).iso / files / umich / telecomm / zmdm.zoo / rz.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-04-27  |  28.7 KB  |  1,504 lines

  1. /*
  2.  *                ACKNOWLEDGEMENTS
  3.  *
  4.  *    ZMDM was derived from rz/sz for Unix  posted by 
  5.  *    Chuck Forsberg (...!tektronix!reed!omen!caf ). We
  6.  *    thank him for his excellent code, and for giving
  7.  *    us permission to use and distribute his code and
  8.  *    documentation.
  9.  *
  10.  *    Atari St version by:
  11.  *    Jwahar Bammi
  12.  *     bang:   {any internet host}!dsrgsun.ces.CWRU.edu!bammi
  13.  *     domain: bammi@dsrgsun.ces.CWRU.edu
  14.  *    GEnie:    J.Bammi
  15.  */
  16.  
  17. #include "config.h"
  18. #define RVERSION "rz 3.01 5-25-89"
  19. #define RSTVERSION "$Revision: 1.72 $ $Date: 1991/04/27 22:12:49 $"
  20. #define OS    "Unix V7/BSD"
  21.  
  22. /* #define RDEBUG */            /* a lot of debugging garb */
  23.  
  24. /*
  25.  *    ATARI ST series implementation notes:
  26.  *
  27.  *        - the following command line options were removed as they
  28.  *          were either  not applicable to the ST environment or
  29.  *          were not deemed reasonable (by me - ofcourse).
  30.  *            1    Not Applicable here as we have a seperate
  31.  *                serial port.
  32.  *            7    In this day and age? Forget it, get another m/c.
  33.  *            a/b    Ascii/Binary - the receive mode (if not
  34.  *                over-ridden by the sender) is automatically
  35.  *                selected depending on the extention given
  36.  *                in the incoming file name. This idea was
  37.  *                present in earlier rz/sz, i wonder why such
  38.  *                a convenient feature was dropped (Chuck ??).
  39.  *                This feature is relevant to ZMODEM only in rz,
  40.  *                as the sender determines the file mode in
  41.  *                XMODEM/YMODEM transfers.
  42.  *                B    Note that `B' has a special meaning.
  43.  *                Specifying -B will force override to
  44.  *                binary mode for each incoming file. Useful
  45.  *                 when doing St-to-St transfers.
  46.  *            D    There is no /dev/null on the ST's
  47.  *            u    not applicable to TOS. Upper and lower
  48.  *                case file names are the same. All the
  49.  *                applicable routines like uncap() and
  50.  *                IsAnyLower() were zapped.
  51.  *
  52.  *        - The    [-][v]rzCOMMAND style of invocation was dropped
  53.  *          as there is no good way to do pipes without the 
  54.  *          microRtx kernal. All references to Pipe and popen()
  55.  *          were zapped.
  56.  *        - Verbose is always set to 2 by automatically, as we know that
  57.  *          stdout != stderr. This can be overridden
  58.  *          by specifying -q to ensure that Verbose = 0
  59.  *        - The idea of a PUBDIR and Restricted paths in the origonal
  60.  *          code  was dropped totally as it is not applicable
  61.  *          to the single owner ST environment. 1 man 1 machine.
  62.  *        - CRCTABLE is default always, hey we have plenty of memory!.
  63.  *        - LOGFILE renamed to 'rzlog/szlog' as we don't always have
  64.  *          a meaningful environment to pick up TMPDIR from (like when
  65.  *          running from the desktop).
  66.  *            - When a subdirectory in an incoming path name is not
  67.  *          present it is created.
  68.  *        - The file mode transmitted is 0S00 where S is derived from
  69.  *          the Read/Write attribute of the file on the ST
  70.  *        - When a file mode is received, only the owner bits are
  71.  *          are checked. If it was read only (r--) on the Unix sytem
  72.  *          then it is given read only attribute on the ST, read-write
  73.  *          otherwise.
  74.  *        - Of course all the I/O was completely redone on the ST.
  75.  *        - You will find two versions of VARARGS routines like log,
  76.  *          one that takes int args, and the other that takes long
  77.  *          (address) args, since sizeof(int) != sizeof(long)
  78.  *          and sizeof(int) != sizeof(pointer) on the ST.
  79.  *
  80.  *    ST v1.01
  81.  *     added support for 32 bit CRC's for Zmodem ++jrb
  82.  *
  83.  *    ST v1.2
  84.  *     added -B ++jrb
  85.  *     added all the recursive stuff
  86.  *     added remote
  87.  */
  88.         
  89. /*% cc -DNFGVMIN -DCRCTABLE -K -O % -o rz; size rz
  90.  *
  91.  * rz.c By Chuck Forsberg
  92.  *
  93.  *    cc -O rz.c -o rz        USG (3.0) Unix
  94.  *     cc -O -DV7  rz.c -o rz        Unix V7, BSD 2.8 - 4.3
  95.  *
  96.  *    ln rz rb            For either system
  97.  *
  98.  *    ln rz /usr/bin/rzrmail        For remote mail.  Make this the
  99.  *                    login shell. rzrmail then calls
  100.  *                    rmail(1) to deliver mail.
  101.  *
  102.  *        define CRCTABLE to use table driven CRC
  103.  *
  104.  *  Unix is a trademark of Western Electric Company
  105.  *
  106.  * A program for Unix to receive files and commands from computers running
  107.  *  Professional-YAM, PowerCom, YAM, IMP, or programs supporting XMODEM.
  108.  *  rz uses Unix buffered input to reduce wasted CPU time.
  109.  *
  110.  * Iff the program is invoked by rzCOMMAND, output is piped to 
  111.  * "COMMAND filename"
  112.  *
  113.  *  Some systems (Venix, Coherent, Regulus) may not support tty raw mode
  114.  *  read(2) the same way as Unix. ONEREAD must be defined to force one
  115.  *  character reads for these systems. Added 7-01-84 CAF
  116.  *
  117.  *  Alarm signal handling changed to work with 4.2 BSD 7-15-84 CAF 
  118.  *
  119.  *  NFGVMIN Added 1-13-85 CAF for PC-AT Xenix systems where c_cc[VMIN]
  120.  *  doesn't seem to work (even though it compiles without error!).
  121.  *
  122.  *  USG UNIX (3.0) ioctl conventions courtesy  Jeff Martin
  123.  */
  124.  
  125.  
  126. #include "zmdm.h"
  127. #include "common.h"
  128. #include "zmodem.h"
  129.  
  130. static unsigned long SaveIntr;
  131.  
  132. #ifndef Vsync             /* Atari forgot these in osbind.h */
  133. #define Vsync()    xbios(37)
  134. #endif
  135.  
  136. #ifndef Supexec
  137.         /* Some versions of osbind don't define Supexec */
  138. #define Supexec(X) xbios(38,X)
  139. #endif
  140.  
  141. #if (MWC || MANX || __GNUC__)
  142. extern FILE  *fopen();
  143. #else
  144. extern FILE  *fopen(), *fopenb();
  145. #endif
  146.  
  147. #ifndef STANDALONE
  148. #define RETURN return
  149. #else
  150. static void RETURN();
  151. void bibis(n) int n; {} /* dummy */
  152. #endif 
  153.  
  154. static long start_time;
  155.  
  156. #ifndef STANDALONE
  157. /* called by simulated signal interrupt or terminate to clean things up */
  158. void bibi(n)
  159. int n;
  160. {
  161.  
  162.     if (Zmodem)
  163.         zmputs(Attn);
  164.     canit(); mode(0);
  165.     fprintf(STDERR, "\r\nrz: caught signal %d; exiting", n);
  166.     if (fout != -1)
  167.     {
  168.         if (stfclose(fout) != 0)
  169.         {
  170.             fprintf(STDERR, "\r\nfile close ERROR\n");
  171.         }
  172.         fout = (-1);
  173.  
  174.     }
  175.  
  176. #ifdef RDEBUG
  177.     if (logf != (FILE *)NULL)
  178.         fclose(logf);
  179. #endif
  180.     aexit(128+n);
  181. }
  182. #endif
  183.  
  184. #ifdef STANDALONE
  185. int main(argc, argv)
  186. #else
  187. int dorz(argc, argv)
  188. #endif /* STANDALONE */
  189. int argc;
  190. char **argv;
  191. {
  192.     register char *cp;
  193.     register int npats;
  194.     char **patts;
  195.     int exitcode;
  196.  
  197. #ifdef STANDALONE
  198. #if (MWC || __GNUC__)
  199. #ifdef MWC
  200.     extern char *lmalloc();
  201. #else
  202. #define lmalloc malloc
  203.     extern void *lmalloc(unsigned long);
  204. #endif
  205. #endif
  206.  
  207.     /* Set up Dta */
  208.     Fsetdta(&statbuf);
  209.  
  210.     /* Get screen rez */
  211.     rez = Getrez();
  212.     drv_map = Drvmap();
  213.  
  214. #if (MWC || MANX || __GNUC__)
  215. #ifndef DYNABUF
  216. #if (MWC || __GNUC__)
  217.     if((bufr = (unsigned char *)lmalloc((unsigned long)BBUFSIZ))
  218.                      == (unsigned char *)NULL)
  219. #else
  220.     if((bufr = (unsigned char *)Malloc((unsigned long)BBUFSIZ))
  221.                      == (unsigned char *)NULL)
  222. #endif
  223. #else
  224.     if((bufr = dalloc()) == (unsigned char *)NULL)
  225. #endif /* DYNABUF */
  226.     {
  227. #ifdef REMOTE
  228.         Bauxws("Sorry, could not allocate enough memory\r\n");
  229. #else
  230.         Bconws("Sorry, could not allocate enough memory\r\n");
  231. #endif
  232.  
  233.         Pterm(4);
  234.     }
  235. #else /* MWC || MANX */
  236. #ifdef DYNABUF
  237.     if((bufr = dalloc()) == (unsigned char *)NULL)
  238.     {
  239. #ifdef REMOTE
  240.         Bauxws("Sorry, could not allocate enough memory\r\n");
  241. #else
  242.         Bconws("Sorry, could not allocate enough memory\r\n");
  243. #endif
  244.         Pterm(5);
  245.     }
  246. #endif /* DYNABUF */
  247. #endif /* MWC || MANX */
  248.  
  249. #ifndef REMOTE
  250.     STDERR = stderr;
  251. #else
  252. #ifndef DLIBS
  253.     if((STDERR = fopen("aux:", "rw")) == (FILE *)NULL)
  254.     {
  255.         Bauxws("Could not Open Aux Stream for Stderr\r\n");
  256.         finish();
  257.     }
  258.     setbuf(STDERR, (char *)NULL);
  259. #else
  260.     STDERR = stdaux;
  261. #endif /* DLIBS */
  262.     
  263. #endif /* REMOTE */
  264.  
  265.     {
  266.         int speed;
  267.         speed = getbaud();
  268.         Baudrate = BAUD_RATE(speed);
  269.         SetIoBuf();
  270.         Rsconf(speed, 0,-1,-1,-1,-1);
  271.         Vsync(); Vsync();
  272.     }
  273.  
  274. #endif /* STANDALONE */
  275.  
  276.     SendType = 0;
  277.     Rxtimeout = 100;
  278.     exitcode = 0;
  279.  
  280.     initz();
  281.  
  282. #ifndef STANDALONE
  283.     chkinvok(argv[0]);     /* if called as  'rb' set flag */
  284. #else
  285.     Progname = "rz";
  286. #endif
  287.  
  288.     npats = 0;
  289.     SaveIntr = Setexc(0x0102, -1L);
  290.     BusErr   = Setexc(2, -1L);
  291.     AddrErr  = Setexc(3, -1L);
  292.     vdebug = 0;
  293.  
  294.     while (--argc)
  295.     {
  296.         cp = *++argv;
  297.         if (*cp == '-')
  298.         {
  299.             while( *++cp)
  300.             {
  301.                 switch(*cp)
  302.                 {
  303.                 case '+':
  304.                     Lzmanag = ZMAPND; break;
  305.                 case 'B':
  306.                     ForceBinary=TRUE; break;
  307.                 case 'c':
  308.                     Crcflg=TRUE; break;
  309.                 case 'D':
  310.                     Nflag = TRUE; break;
  311.                 case 'e':
  312.                     Zctlesc = 1; break;
  313.                 case 'p':
  314.                     Lzmanag = ZMPROT;  break;
  315.                 case 'q':
  316.                     Quiet=TRUE; Verbose=0; break;
  317.                 case 't':
  318.                     if (--argc < 1) {
  319.                         rusage();
  320.                         RETURN(1);
  321.                     }
  322.                     Rxtimeout = atoi(*++argv);
  323.                     if (Rxtimeout<10 || Rxtimeout>1000)
  324.                     {
  325.                         rusage();
  326.                         RETURN(1);
  327.                     }
  328.                     break;
  329.                 case 'w':
  330.                     if (--argc < 1) {
  331.                         rusage();
  332.                         RETURN(1);
  333.                     }
  334.                     Zrwindow = atoi(*++argv);
  335.                     break;
  336.                 case 'v':
  337.                     ++Verbose; break;
  338.                 case 'y':
  339.                     Rxclob=FALSE; break;
  340.                 default:
  341.                     rusage();
  342.                     RETURN(1);
  343.                 }
  344.             }
  345.         }
  346.         else if ( !npats && argc>0)
  347.         {
  348.             if (argv[0][0])
  349.             {
  350.                 npats=argc;
  351.                 patts=argv;
  352.             }
  353.         }
  354.     }
  355.  
  356.     if (npats > 1)
  357.     {
  358.         rusage();
  359.         RETURN(1);
  360.     }
  361.  
  362. #ifdef RDEBUG
  363.     if (Verbose > 2)
  364.     {
  365.         if ((logf = fopen(RLOGFILE, "a"))== (FILE *)NULL)
  366.         {
  367.             fprintf(STDERR, "Can't open log file %s\n",RLOGFILE);
  368.             RETURN(0200);
  369.         }
  370.         fprintf(logf, "Progname=%s\n", Progname);
  371.         vdebug = 1;
  372.     }
  373. #endif
  374.  
  375.     if ( !Quiet)
  376.     {
  377.         if (Verbose == 0)
  378.             Verbose = 2;
  379.     }
  380.  
  381.     Setexc(0x0102, bibi);
  382.  
  383.     Setexc(2, buserr);
  384.     Setexc(3, addrerr);
  385.  
  386.     if((exitcode = setjmp(abrtjmp)))
  387.     {
  388.         /* on Contrl-C */
  389.         canit();
  390.         Setexc(2, BusErr);
  391.         Setexc(3, AddrErr);
  392.         Setexc(0x0102, SaveIntr);
  393.         RETURN(exitcode);
  394.     }
  395.     
  396.     if(setjmp(busjmp))
  397.     {
  398.         /* On a bus error - instead of 2 bombs */
  399.         fprintf(STDERR,"\r\nFATAL: Bus Error\n\n");
  400. #ifdef RDEBUG
  401.         if(logf != (FILE *)NULL)
  402.             fclose(logf);
  403. #endif
  404.         if(fout != -1)
  405.         {
  406.             if (stfclose(fout) != 0)
  407.             {
  408.                 fprintf(STDERR, "\r\nfile close ERROR\n");
  409.             }
  410.             fout = (-1);
  411.         }
  412.         canit();
  413.         Setexc(2, BusErr);
  414.         Setexc(3, AddrErr);
  415.         Setexc(0x0102, SaveIntr);
  416.  
  417.         RETURN(2);
  418.     }
  419.  
  420.     if(setjmp(addrjmp))
  421.     {
  422.         /* On address error - instead of 3 bombs */
  423.         fprintf(STDERR,"\r\nFATAL: Address Error\n\n");
  424. #ifdef RDEBUG
  425.         if(logf != (FILE *)NULL)
  426.             fclose(logf);
  427. #endif
  428.         if(fout != -1)
  429.         {
  430.             if (stfclose(fout) != 0)
  431.             {
  432.                 fprintf(STDERR, "\r\nfile close ERROR\n");
  433.             }
  434.             fout = (-1);
  435.         }
  436.         canit();
  437.         Setexc(2, BusErr);
  438.         Setexc(3, AddrErr);
  439.         Setexc(0x0102, SaveIntr);
  440.  
  441.         RETURN(3);
  442.     }
  443.  
  444.     mode(1);
  445.  
  446.     if (wcreceive(npats, patts)==ERROR)
  447.     {
  448.         exitcode=0200;
  449.         canit();
  450.     }
  451.  
  452.     mode(0);
  453.     if (exitcode && !Zmodem)    /* bellow again with all thy might. */
  454.         canit();
  455.  
  456. #ifdef RDEBUG
  457.     if(logf != (FILE *)NULL)
  458.         fclose(logf);
  459. #endif
  460.  
  461.     if(fout != -1)
  462.     {
  463.         if (stfclose(fout) != 0)
  464.         {
  465.             fprintf(STDERR, "\r\nfile close ERROR\n");
  466.         }
  467.         fout = (-1);
  468.     }
  469.     Setexc(2, BusErr);
  470.     Setexc(3, AddrErr);
  471.     Setexc(0x0102, SaveIntr);
  472.  
  473.      RETURN(exitcode); 
  474. }
  475.  
  476. #ifdef STANDALONE
  477. static void RETURN(n)
  478. int n;
  479. {
  480.     ResetIoBuf();
  481. #if (MWC || MANX || __GNUC__)
  482. #ifndef DYNABUF
  483.     free(bufr);
  484. #else
  485.     Mfree(bufr);
  486. #endif
  487. #else
  488. #ifdef DYNABUF
  489.     Mfree(bufr);
  490. #endif
  491. #endif
  492.  
  493.     exit(n);
  494. }
  495. #endif /* STANDALONE */
  496.  
  497. int rusage()
  498. {
  499.     fprintf(STDERR,
  500.         "%s for %s by ST Enthusiasts at Case Western Reserve University\n",
  501.           RSTVERSION, STOS);
  502.     fprintf(STDERR, "\tBased on %s for %s by Chuck Forsberg\n\n",
  503.         RVERSION, OS);
  504.  
  505.     fprintf(STDERR,"Usage:    rz [-Bepqtvwy]        (ZMODEM Batch)\n");
  506.     fprintf(STDERR,"or    rb [-qtv]        (YMODEM Batch)\n");
  507.     fprintf(STDERR,"or    rz [-cqtv] file            (XMODEM or XMODEM-1k)\n");
  508.     fprintf(STDERR,"      -B Force Binary Mode transfers\n");
  509.     fprintf(STDERR,"      -v Verbose more v's give more info\n");
  510.     fprintf(STDERR,"          -q Quiet suppresses verbosity\n");
  511.     fprintf(STDERR,"      -t TIM Change timeout to TIM tenths of seconds\n");
  512.     fprintf(STDERR,"      -c Use 16 bit CRC    (XMODEM)\n");
  513.     fprintf(STDERR,"      -p Protect existing dest. file by skipping\n");
  514.     fprintf(STDERR,"         transfer if the dest. file exists (ZMODEM ONLY)\n\n");
  515.     fprintf(STDERR,"      -e Escape control characters (Z)\n");
  516.     fprintf(STDERR,"      -w N Window is N bytes (Z)\n");
  517.  
  518.  
  519.     if(fout != -1)
  520.     {
  521.         if (stfclose(fout) != 0)
  522.         {
  523.             fprintf(STDERR, "\r\nfile close ERROR\n");
  524.         }
  525.         fout = (-1);
  526.     }
  527.  
  528. #ifdef RDEBUG
  529.     if(logf != (FILE *)NULL)
  530.         fclose(logf);
  531. #endif
  532.  
  533.     return(1);
  534. }
  535.  
  536.  
  537. /*
  538.  * Let's receive something already.
  539.  */
  540. int wcreceive(argc, argp)
  541. int argc;
  542. char **argp;
  543. {
  544.     register int c;
  545.  
  546.     if (Batch || argc==0)
  547.     {
  548.             Crcflg= 1;
  549.         if ( !Quiet)
  550. #ifndef REMOTE
  551.             fprintf(STDERR, "\n%s: ready (CTRL-C to cancel)\n\n",
  552.                 Progname);
  553. #else
  554.             fprintf(STDERR, "\n%s: ready\n\n",
  555.                 Progname);
  556. #endif
  557.         if (c=tryz())
  558.         {
  559.             if (c == ZCOMPL)
  560.                 return OK;
  561.             if (c == ERROR)
  562.                 goto fubar;
  563.             c = rzfiles();
  564.             if (c)
  565.                 goto fubar;
  566.         }
  567.         else
  568.         {
  569.             for (;;)
  570.             {
  571.                 if (wcrxpn(secbuf)== ERROR)
  572.                     goto fubar;
  573.                 if (secbuf[0]==0)
  574.                     return OK;
  575.                 if (procheader(secbuf) == ERROR)
  576.                     goto fubar;
  577.                 if (wcrx()==ERROR)
  578.                     goto fubar;
  579.             }
  580.         }
  581.     } 
  582.     else
  583.     {
  584.         Bytesleft = DEFBYTL; Filemode = 0; Modtime = 0L;
  585.  
  586.         procheader(""); strcpy(Pathname, *argp);
  587. #ifndef REMOTE
  588.         fprintf(STDERR, "\n%s: ready to receive %s (CTRL-C to Cancel)\n\n",
  589.             Progname, Pathname);
  590. #else
  591.         fprintf(STDERR, "\n%s: ready to receive %s\n\n",
  592.             Progname, Pathname);
  593. #endif
  594.  
  595. #ifdef RDEBUG
  596.         if(logf != (FILE *)NULL)
  597.             fprintf(logf, "\nrz: ready to receive %s ", Pathname);
  598. #endif
  599.  
  600.         if((fout = stfopen(Pathname,"w")) <= 0)
  601.             return ERROR;
  602.         if (wcrx()==ERROR)
  603.             goto fubar;
  604.     }
  605.     return OK;
  606.  
  607. fubar:
  608.     canit();
  609.     Modtime = 1;
  610.     if (fout != -1)
  611.     {
  612.         if (stfclose(fout) != 0)
  613.         {
  614.             fprintf(STDERR, "\r\nfile close ERROR\n");
  615.         }
  616.         fout = (-1);
  617.     }
  618.  
  619.     return ERROR;
  620. }
  621.  
  622.  
  623. /*
  624.  * Fetch a pathname from the other end as a C ctyle ASCIZ string.
  625.  * Length is indeterminate as long as less than Blklen
  626.  * A null string represents no more files (YMODEM)
  627.  */
  628. int wcrxpn(rpn)
  629. char *rpn;    /* receive a pathname */
  630. {
  631.     register int c;
  632.  
  633.     PURGELINE;
  634.  
  635. et_tu:
  636.     Firstsec=TRUE;  Eofseen=FALSE;
  637.     sendline(Crcflg?WANTCRC:NAK);
  638.     Lleft=0;    /* Do read next time ... */
  639.     while ((c = wcgetsec(rpn, 100)) != 0)
  640.     {
  641.         llog( "Pathname fetch returned %d\n", c);
  642.         if (c == WCEOT)
  643.         {
  644.             sendline(ACK);
  645.             Lleft=0;    /* Do read next time ... */
  646.             readline(1);
  647.             goto et_tu;
  648.         }
  649.         return ERROR;
  650.     }
  651.     sendline(ACK);
  652.     return OK;
  653. }
  654.  
  655. /*
  656.  * Adapted from CMODEM13.C, written by
  657.  * Jack M. Wierda and Roderick W. Hart
  658.  */
  659.  
  660. int wcrx()
  661. {
  662.     register int sectnum, sectcurr;
  663.     register char sendchar;
  664.     int cblklen;            /* bytes to dump this block */
  665.  
  666.     Firstsec=TRUE;sectnum=0; Eofseen=FALSE;
  667.     sendchar=Crcflg?WANTCRC:NAK;
  668.  
  669.     for (;;)
  670.     {
  671.         sendline(sendchar);    /* send it now, we're ready! */
  672.         Lleft=0;    /* Do read next time ... */
  673.         sectcurr=wcgetsec(secbuf, (sectnum&0177)?50:130);
  674.         report(sectcurr);
  675.         if (sectcurr==(sectnum+1 &Wcsmask))
  676.         {
  677.             sectnum++;
  678.             cblklen = Bytesleft>Blklen ? Blklen:Bytesleft;
  679.             if (putsec(secbuf, cblklen)==ERROR)
  680.                 return ERROR;
  681.             if ((Bytesleft-=cblklen) < 0)
  682.                 Bytesleft = 0;
  683.             sendchar=ACK;
  684.         }
  685.         else if (sectcurr==(sectnum&Wcsmask))
  686.         {
  687.             log2( "Received dup Sector\n");
  688.             sendchar=ACK;
  689.         }
  690.         else if (sectcurr==WCEOT)
  691.         {
  692.             if (closeit(0L))
  693.                 return ERROR;
  694.             sendline(ACK);
  695.             Lleft=0;    /* Do read next time ... */
  696.             return OK;
  697.         }
  698.         else if (sectcurr==ERROR)
  699.             return ERROR;
  700.         else
  701.         {
  702.             log2( "Sync Error\n");
  703.             return ERROR;
  704.         }
  705.     }
  706. }
  707.  
  708.  
  709. /*
  710.  * Wcgetsec fetches a Ward Christensen type sector.
  711.  * Returns sector number encountered or ERROR if valid sector not received,
  712.  * or CAN CAN received
  713.  * or WCEOT if eot sector
  714.  * time is timeout for first char, set to 4 seconds thereafter
  715.  ***************** NO ACK IS SENT IF SECTOR IS RECEIVED OK **************
  716.  *    (Caller must do that when he is good and ready to get next sector)
  717.  */
  718. int wcgetsec(rxbuf, maxtime)
  719. char *rxbuf;
  720. int maxtime;
  721. {
  722.     register int checksum, wcj, firstch;
  723.     register unsigned int oldcrc;
  724.     register char *p;
  725.     int sectcurr;
  726.  
  727.     for (Lastrx=errors=0; errors<RETRYMAX; errors++)
  728.     {
  729.         if ((firstch=readline(maxtime))==STX)
  730.         {
  731.             Blklen=KSIZE; goto get2;
  732.         }
  733.         if (firstch==SOH)
  734.         {
  735.             Blklen=SECSIZ;
  736. get2:
  737.             sectcurr=readline(1);
  738.             if ((sectcurr+(oldcrc=readline(1)))==Wcsmask)
  739.             {
  740.                 oldcrc=checksum=0;
  741.                 for (p=rxbuf,wcj=Blklen; --wcj>=0; )
  742.                 {
  743.                     if ((firstch=readline(1)) < 0)
  744.                         goto bilge;
  745.                     oldcrc=updcrc(firstch, oldcrc);
  746.                     checksum += (*p++ = firstch);
  747.                 }
  748.                 if ((firstch=readline(1)) < 0)
  749.                     goto bilge;
  750.                 if (Crcflg)
  751.                 {
  752.                     oldcrc=updcrc(firstch, oldcrc);
  753.                     if ((firstch=readline(1)) < 0)
  754.                         goto bilge;
  755.                     oldcrc=updcrc(firstch, oldcrc);
  756.                     if (oldcrc & 0xFFFF)
  757.                         llog("CRC=0%o\n", oldcrc);
  758.                     else
  759.                     {
  760.                         Firstsec=FALSE;
  761.                         return sectcurr;
  762.                     }
  763.                 }
  764.                 else if (((checksum-firstch)&Wcsmask)==0)
  765.                 {
  766.                     Firstsec=FALSE;
  767.                     return sectcurr;
  768.                 }
  769.                 else
  770.                     log2( "Checksum Error\n");
  771.             }
  772.             else
  773.                 log2("Sector number garbled 0%o 0%o\n",
  774.                  sectcurr, oldcrc);
  775.         }
  776.         /* make sure eot really is eot and not just mixmash */
  777.  
  778.         else if (firstch==EOT && Lleft==0)
  779.             return WCEOT;
  780.  
  781.         else if (firstch==CAN)
  782.         {
  783.             if (Lastrx==CAN)
  784.             {
  785.                 log2( "Sender CANcelled\n");
  786.                 return ERROR;
  787.             }
  788.             else
  789.             {
  790.                 Lastrx=CAN;
  791.                 continue;
  792.             }
  793.         }
  794.         else if (firstch==TIMEOUT)
  795.         {
  796.             if (Firstsec)
  797.                 goto humbug;
  798. bilge:
  799.             log2( "Timeout\n");
  800.         }
  801.         else
  802.             llog( "Got 0%o sector header\n", firstch);
  803.  
  804. humbug:
  805.         Lastrx=0;
  806.         while(readline(1)!=TIMEOUT)
  807.             ;
  808.         if (Firstsec)
  809.         {
  810.             sendline(Crcflg?WANTCRC:NAK);
  811.             Lleft=0;    /* Do read next time ... */
  812.         }
  813.         else
  814.         {
  815.             maxtime=40; sendline(NAK);
  816.             Lleft=0;    /* Do read next time ... */
  817.         }
  818.     }
  819.     /* try to stop the bubble machine. */
  820.     canit();
  821.     return ERROR;
  822. }
  823.  
  824.  
  825.  
  826. unsigned int timep[2];
  827.  
  828. /*
  829.  * Process incoming file information header
  830.  */
  831. int procheader(name)
  832. char *name;
  833. {
  834.     register char  *p;
  835.     register int dot;
  836.     char openmode[4];
  837. #ifdef __GNUC__
  838.     extern size_t strlen();
  839. #else
  840.     extern int strlen();
  841. #endif
  842.  
  843.     /* convert to ST style path names */
  844.     for( p = name; *p != '\0'; p++)
  845.     {
  846.         if(*p == '/')
  847.             *p = '\\';
  848.     }
  849.     
  850.     /* pick out the last extention in the filename in each part of path */
  851.     while(p != name)
  852.     {
  853.         dot = 0; p-- ;
  854.         while((p != name) && (*p != '\\'))
  855.         {
  856.             if(*p == '.')
  857.             {
  858.                 if(dot == 0)
  859.                 {
  860.                     dot = 1;
  861.                 }
  862.                 else
  863.                 {
  864.                    /* replace all but the last dot with '_' */
  865.                     *p = '_';
  866.                 }
  867.             }
  868.             p--;
  869.         }
  870.     }
  871.                 
  872.     /* set default parameters and overrides */
  873.     strcpy(openmode,"w");
  874.  
  875.     Thisbinary = isbinary(name);
  876.  
  877.     if (Lzmanag)
  878.         zmanag = Lzmanag;
  879.  
  880.     /*
  881.      *  Process ZMODEM remote file management requests
  882.      */
  883.     if ( zconv == ZCNL)    /* Remote ASCII override */
  884.         Thisbinary = 0;
  885.     if (zconv == ZCBIN)    /* Remote Binary override */
  886.         ++Thisbinary;
  887.     else if (zmanag == ZMAPND)
  888.         strcpy(openmode, "a");
  889.  
  890.     if (ForceBinary == TRUE )    /* local binary force override */
  891.         ++Thisbinary;
  892.  
  893.     /* ZMPROT check for existing file */
  894.     if (!Rxclob && (zmanag&ZMMASK) != ZMCLOB && existf(name))
  895.     {
  896.         return ERROR;
  897.     }
  898.  
  899. /* ATARI ST NOTE:
  900.  *    We will not accept rooted paths ie. paths that begin in '\' or '.\'
  901.  *    If the incoming filename is rooted, we skip the beginning
  902.  *    '\'   '.\'  or  '..\'
  903.  */
  904.  
  905.     if( (name[0] == '\\') || (name[0] == '.')  )
  906.     {
  907.         /* skip over the leading stuff */
  908.         if(name[0] == '\\')
  909.             name = &name[1];
  910.         else
  911.         {
  912.             if(name[1] == '.')
  913.                 name = &name[3];  /* Skip the "..\" */
  914.             else
  915.                 name = &name[2];  /* Skip the ".\"  */
  916.         }
  917.     }
  918.  
  919.     /* ST addition, create any dierctories in the path that don't exist */
  920.     if( pathensure(name) == ERROR)
  921.         return ERROR;
  922.  
  923.     Bytesleft = DEFBYTL; Filemode = 0; Modtime = 0L;
  924.  
  925.     p = name + 1 + (int)strlen(name);
  926.     if (*p)
  927.     {    /* file coming from Unix or DOS system */
  928.         sscanf(p, "%ld%lo%o", &Bytesleft, &Modtime, &Filemode);
  929.         if(Modtime)
  930.             unix2st(Modtime, &timep[0], &timep[1]);
  931.         else
  932.             timep[0] = timep[1] = 0;
  933. #ifndef REMOTE
  934.         if (Verbose)
  935.         {
  936.             fprintf(STDERR,
  937.             "\nIncoming:\n\tName:\t%s\n\tBytes:\t%ld\n\
  938. \tModTime: %02d/%02d/%04d  %02d:%02d:%02d\n\tMode:\t0%03o\n\tBufSize: %ld\n\n",
  939.               name, Bytesleft, 
  940.               (timep[1] >> 5) & 0x0f,
  941.               timep[1] & 0x1f,
  942.               ((timep[1] >> 9)  & 0x7f) + 1980,
  943.               (timep[0] >> 11) & 0x1f,
  944.               (timep[0] >> 5)  & 0x3f,
  945.               timep[0] & 0x1f, (Filemode & (unsigned int)0777), (long)BBUFSIZ);
  946.  
  947. #ifdef RDEBUG
  948.             if(logf != (FILE *)NULL)
  949.                 fprintf(logf,  "Incoming: %s %ld %lo %o\n",
  950.                   name, Bytesleft, Modtime, Filemode);
  951. #endif
  952.  
  953.         }
  954. #endif /* REMOTE */
  955.  
  956.     }
  957.     else
  958.     {        /* File coming from CP/M system */
  959.         for (p=name; *p; ++p)        /* change / to _ */
  960.             if ( *p == '/')
  961.                 *p = '_';
  962.  
  963.         if ( *--p == '.')        /* zap trailing period */
  964.             *p = 0;
  965.     }
  966.     
  967.     strcpy(Pathname, name);
  968. #ifndef REMOTE
  969.     if (Verbose)
  970.     {
  971.         fprintf(STDERR,  "Receiving %s %s [mode %s]\n\n",
  972.           name, Thisbinary?"BIN":"ASCII", openmode);
  973.  
  974. #ifdef RDEBUG
  975.         if(logf != (FILE *)NULL)
  976.             fprintf(logf,  "Receiving %s %s %s\n",
  977.               name, Thisbinary?"BIN":"ASCII", openmode);
  978. #endif
  979.  
  980.     }
  981. #endif /* REMOTE */
  982.  
  983.     if ((fout=stfopen(name, openmode)) <= 0)
  984.         return ERROR;
  985.  
  986.     return OK;
  987. }
  988.  
  989. /*
  990.  * Putsec writes the n characters of buf to receive file fout.
  991.  *  If not in binary mode,  all characters
  992.  *  starting with CPMEOF are discarded.
  993.  */
  994. int putsec(buf, n)
  995. unsigned char *buf;
  996. register int n;
  997. {
  998.     register unsigned char *p;
  999.  
  1000.     if(n == 0)
  1001.         return OK;
  1002.     
  1003.     if (Thisbinary)
  1004.     {
  1005.         for (p=buf; --n>=0; p++ )
  1006.         {
  1007.             if(stputc( *p, fout) < 0)
  1008.             {
  1009.                 fprintf(STDERR, "\r\nError while Writing file\n");
  1010.                 return ERROR;
  1011.             }
  1012.         }
  1013.     }
  1014.     else
  1015.     {
  1016.         if (Eofseen)
  1017.             return OK;
  1018.  
  1019.         for (p=buf; --n>=0; p++ )
  1020.         {
  1021.             if (*p == CPMEOF)
  1022.             {
  1023.                 Eofseen=TRUE;
  1024.                 return OK;
  1025.             }
  1026.             if(*p == '\n')
  1027.             {
  1028.                 if(stputc('\r' ,fout) < 0)
  1029.                 {
  1030.                     fprintf(STDERR, "\r\nError while Writing file\n");
  1031.                     return ERROR;
  1032.                 }
  1033.             }
  1034.             if(stputc(*p ,fout) < 0)
  1035.             {
  1036.                 fprintf(STDERR,"\r\nError while Writing file\n");
  1037.                 return ERROR;
  1038.             }
  1039.         }
  1040.     }
  1041.  
  1042.     return OK;
  1043. }
  1044.  
  1045. /*
  1046.  * Log an error only if high verbose
  1047.  */
  1048. /*VARARGS1*/
  1049. void llog(s,p,u)
  1050. char *s;
  1051. int p, u;
  1052. {
  1053.     if (Verbose < 3)
  1054.         return;
  1055. #ifdef RDEBUG
  1056.     fprintf(logf, "error %d: ", errors);
  1057.     fprintf(logf, s, p, u);
  1058. #endif
  1059.  
  1060.     fprintf(STDERR, "\nerror %d: ", errors);
  1061.     fprintf(STDERR, s, p, u);
  1062. }
  1063.  
  1064.  
  1065.  
  1066. #ifndef STANDALONE
  1067. /*
  1068.  * If called as rb use YMODEM protocol
  1069.  */
  1070. void chkinvok(s)
  1071. char *s;
  1072. {
  1073.     Progname = s;
  1074.     if (s[0]=='r' && s[1]=='b')
  1075.         Nozmodem = TRUE;
  1076. }
  1077. #endif
  1078.  
  1079. /*
  1080.  * Initialize for Zmodem receive attempt, try to activate Zmodem sender
  1081.  *  Handles ZSINIT frame
  1082.  *  Return ZFILE if Zmodem filename received, -1 on error,
  1083.  *   ZCOMPL if transaction finished,  else 0
  1084.  */
  1085. int tryz()
  1086. {
  1087.     register int n, c;
  1088.     register int cmdzack1flg;
  1089.  
  1090.     if (Nozmodem)        /* Check for "rb" program name */
  1091.         return 0;
  1092.  
  1093.  
  1094.     for (n=Zmodem?15:5; --n>=0; )
  1095.     {
  1096.         /* Set buffer length (0) and capability flags */
  1097.         stohdr(0L);
  1098. #if 0
  1099.         Txhdr[ZF0] = CANFC32|CANFDX|CANOVIO|CANBRK;
  1100. #else
  1101.         Txhdr[ZF0] = CANFC32|CANFDX|CANOVIO;
  1102. #endif
  1103.         if (Zctlesc)
  1104.             Txhdr[ZF0] |= TESCCTL;
  1105.         Txhdr[ZF0] |= CANRLE;
  1106.         Txhdr[ZF1] = CANVHDR;
  1107.         /* tryzhdrtype may == ZRINIT */
  1108.         zshhdr(4,tryzhdrtype, Txhdr);
  1109.         if (tryzhdrtype == ZSKIP)    /* Don't skip too far */
  1110.             tryzhdrtype = ZRINIT;    /* CAF 8-21-87 */
  1111. again:
  1112.         switch (zgethdr(Rxhdr, 0))
  1113.         {
  1114.         case ZRQINIT:
  1115.             if (Rxhdr[ZF3] & 0x80)
  1116.                 Usevhdrs = 1;    /* we can var header */
  1117.             continue;
  1118.         case ZEOF:
  1119.             continue;
  1120.         case TIMEOUT:
  1121.             continue;
  1122.         case ZFILE:
  1123.             zconv = Rxhdr[ZF0];
  1124.             zmanag = Rxhdr[ZF1];
  1125.             ztrans = Rxhdr[ZF2];
  1126.             if (Rxhdr[ZF3] & ZCANVHDR)
  1127.                 Usevhdrs = TRUE;
  1128.             tryzhdrtype = ZRINIT;
  1129.             c = zrdata(secbuf, KSIZE);
  1130. /*            mode(3); */
  1131.             if (c == GOTCRCW)
  1132.                 return ZFILE;
  1133.             zshhdr(4,ZNAK, Txhdr);
  1134.             goto again;
  1135.         case ZSINIT:
  1136.             Zctlesc = TESCCTL & Rxhdr[ZF0];
  1137.             if (zrdata(Attn, ZATTNLEN) == GOTCRCW)
  1138.             {
  1139.                 stohdr(1L);
  1140.                 zshhdr(4, ZACK, Txhdr);
  1141.                 goto again;
  1142.             }
  1143.             zshhdr(4, ZNAK, Txhdr);
  1144.             goto again;
  1145.         case ZFREECNT:
  1146.             stohdr(~0L);
  1147.             zshhdr(4, ZACK, Txhdr);
  1148.             goto again;
  1149.         case ZCOMMAND:
  1150.             cmdzack1flg = Rxhdr[ZF0];
  1151.             if (zrdata(secbuf, KSIZE) == GOTCRCW)
  1152.             {
  1153.                 if (cmdzack1flg & ZCACK1)
  1154.                     stohdr(0L);
  1155.                 else
  1156.                     stohdr((long)sys2(secbuf));
  1157.                 PURGELINE;    /* dump impatient questions */
  1158.                 do {
  1159.                     zshhdr(4, ZCOMPL, Txhdr);
  1160.                 }
  1161.                 while (++errors<20 && zgethdr(Rxhdr,1) != ZFIN);
  1162.                 ackbibi();
  1163.                 if (cmdzack1flg & ZCACK1)
  1164.                     exec2(secbuf);
  1165.                 return ZCOMPL;
  1166.             }
  1167.             zshhdr(4, ZNAK, Txhdr); goto again;
  1168.         case ZCOMPL:
  1169.             goto again;
  1170.         default:
  1171.             continue;
  1172.         case ZFIN:
  1173.             ackbibi(); return ZCOMPL;
  1174.         case ZCAN:
  1175.             return ERROR;
  1176.         }
  1177.     }
  1178.     return 0;
  1179. }
  1180.  
  1181. /*
  1182.  * Receive 1 or more files with ZMODEM protocol
  1183.  */
  1184. int rzfiles()
  1185. {
  1186.     register int c;
  1187.  
  1188.     for (;;) {
  1189.         switch (c = rzfile()) {
  1190.         case ZEOF:
  1191.         case ZSKIP:
  1192.             switch (tryz()) {
  1193.             case ZCOMPL:
  1194.                 return OK;
  1195.             default:
  1196.                 return ERROR;
  1197.             case ZFILE:
  1198.                 break;
  1199.             }
  1200.             continue;
  1201.         default:
  1202.             return c;
  1203.         case ERROR:
  1204.             return ERROR;
  1205.         }
  1206.     }
  1207. }
  1208.  
  1209. /*
  1210.  * Receive a file with ZMODEM protocol
  1211.  *  Assumes file name frame is in secbuf
  1212.  */
  1213. int rzfile()
  1214. {
  1215.     register int c, n;
  1216.     long rxbytes;
  1217.     extern void rd_time();
  1218.  
  1219.     Eofseen=FALSE;
  1220.     if (procheader(secbuf) == ERROR) {
  1221.         return (tryzhdrtype = ZSKIP);
  1222.     }
  1223.  
  1224.     n = 20; rxbytes = 0L;
  1225.  
  1226.     Supexec(rd_time);
  1227.     start_time = pr_time;
  1228.  
  1229.     for (;;)
  1230.     {
  1231.         stohdr(rxbytes);
  1232.         zshhdr(4, ZRPOS, Txhdr);
  1233. nxthdr:
  1234.         switch (c = zgethdr(Rxhdr, 0)) {
  1235.         default:
  1236.             vfile("rzfile: zgethdr returned %d", c);
  1237.             return ERROR;
  1238.         case ZNAK:
  1239.         case TIMEOUT:
  1240.             if ( --n < 0)
  1241.             {
  1242.                 vfile("rzfile: zgethdr returned %d", c);
  1243.                 return ERROR;
  1244.             }
  1245.         case ZFILE:
  1246.             zrdata(secbuf, KSIZE);
  1247.             continue;
  1248.         case ZEOF:
  1249.             /* ++jrb */
  1250.             if (rclhdr(Rxhdr) != rxbytes)
  1251.             {
  1252.                 /*
  1253.                      * Ignore eof if it's at wrong place - force
  1254.                      *  a timeout because the eof might have gone
  1255.                      *  out before we sent our zrpos.
  1256.                      */
  1257.  
  1258.                     errors = 0;  goto nxthdr;
  1259.             }
  1260.             if (closeit(rxbytes))
  1261.             {
  1262.                 tryzhdrtype = ZFERR;
  1263.                 vfile("rzfile: closeit returned <> 0");
  1264.                 return ERROR;
  1265.             }
  1266.             vfile("rzfile: normal EOF");
  1267.             return c;
  1268.         case ERROR:    /* Too much garbage in header search error */
  1269.             if ( --n < 0)
  1270.             {
  1271.                 vfile("rzfile: zgethdr returned %d", c);
  1272.                 return ERROR;
  1273.             }
  1274.             zmputs(Attn);
  1275.             continue;
  1276.         case ZSKIP:
  1277.             Modtime = 1;
  1278.             closeit(rxbytes);
  1279.             vfile("rzfile: Sender SKIPPED file");
  1280.             return c;
  1281.         case ZDATA:
  1282.             if (rclhdr(Rxhdr) != rxbytes)
  1283.             {
  1284.                 if(--n < 0)
  1285.                 return ERROR;
  1286.                 
  1287.                 zmputs(Attn);
  1288.                 continue;
  1289.             }
  1290. moredata:
  1291.             switch (c = zrdata(secbuf, KSIZE))
  1292.             {
  1293.             case ZCAN:
  1294.                 vfile("rzfile: zgethdr returned %d", c);
  1295.                 return ERROR;
  1296.             case ERROR:    /* CRC error */
  1297.                 if ( --n < 0)
  1298.                 {
  1299.                     vfile("rzfile: zgethdr returned %d", c);
  1300.                     return ERROR;
  1301.                 }
  1302.                 zmputs(Attn);
  1303.                 continue;
  1304.             case TIMEOUT:
  1305.                 if ( --n < 0)
  1306.                 {
  1307.                     vfile("rzfile: zgethdr returned %d", c);
  1308.                     return ERROR;
  1309.                 }
  1310.                 continue;
  1311.             case GOTCRCW:
  1312.                 n = 20;
  1313.                 
  1314.                 putsec(secbuf, Rxcount);
  1315.                 rxbytes += Rxcount;
  1316.                 lreport(rxbytes);
  1317.                 stohdr(rxbytes);
  1318.                 zshhdr(4, ZACK, Txhdr);
  1319.                 sendline(XON);
  1320.                 goto nxthdr;
  1321.             case GOTCRCQ:
  1322.                 n = 20;
  1323.                 putsec(secbuf, Rxcount);
  1324.                 rxbytes += Rxcount;
  1325.                 lreport(rxbytes);
  1326.                 stohdr(rxbytes);
  1327.                 zshhdr(4, ZACK, Txhdr);
  1328.                 goto moredata;
  1329.             case GOTCRCG:
  1330.                 n = 20;
  1331.                 putsec(secbuf, Rxcount);
  1332.                 rxbytes += Rxcount;
  1333.                 lreport(rxbytes);
  1334.                 goto moredata;
  1335.             case GOTCRCE:
  1336.                 n = 20;
  1337.                 putsec(secbuf, Rxcount);
  1338.                 rxbytes += Rxcount;
  1339.                 lreport(rxbytes);
  1340.                 goto nxthdr;
  1341.             }
  1342.         }
  1343.     }
  1344. }
  1345.  
  1346. /*
  1347.  * Send a string to the modem, processing for \336 (sleep 1 sec)
  1348.  *   and \335 (break signal)
  1349.  */
  1350. void zmputs(s)
  1351. char *s;
  1352. {
  1353.     register int c;
  1354.  
  1355.     while (*s) {
  1356.         switch (c = *s++) {
  1357.         case '\336':
  1358.             stsleep(1); continue;
  1359.         case '\335':
  1360.             sendbrk(); continue;
  1361.         default:
  1362.             sendline(c);
  1363.         }
  1364.     }
  1365. }
  1366.  
  1367.  
  1368.  
  1369. /*
  1370.  * Close the receive dataset, return OK or ERROR
  1371.  */
  1372. int closeit(rxbytes)
  1373. long rxbytes;
  1374. {
  1375.     long end_time;
  1376.     extern void rd_time();
  1377.  
  1378.     if (stfclose(fout) != 0) {
  1379.         fprintf(STDERR, "\r\nfile close ERROR\n");
  1380.         return ERROR;
  1381.     }
  1382.     fout = (-1);
  1383.  
  1384.     Supexec(rd_time);
  1385.     end_time = pr_time;
  1386.  
  1387.     if (Modtime) {
  1388.         touch(Pathname, timep);
  1389.     }
  1390.  
  1391.     /* if it is read only by owner on remote, then it is set
  1392.      * to read only on the ST, all other file modes are
  1393.      * irrelevant.
  1394.      */
  1395.     if (Filemode)
  1396.     {
  1397.         unsigned int fmode;
  1398.  
  1399.         fmode = (unsigned int)(Filemode & 000777);
  1400.         if( ((fmode & 0200) == 0) && ((fmode & 0400) != 0) )
  1401.         {
  1402.             /* it is readonly by owner on the remote, so
  1403.              * make it read only on the ST too
  1404.              */
  1405.             Fattrib(Pathname, 1, 0x01);
  1406.         }
  1407.     }
  1408. #ifndef REMOTE
  1409.     if(rxbytes != 0L)
  1410.         fprintf(STDERR,"\033K\n\n%s Closed\nTransfer Time %ld secs.\tfor %ld bytes\
  1411. \tApprox %ld cps\n\n", Pathname, (end_time - start_time)/200L, rxbytes,
  1412. rxbytes/((end_time - start_time)/200L));
  1413.     else
  1414.         fprintf(STDERR,"\033K\n\n%s Closed\n\n", Pathname);
  1415. #endif
  1416.     lsct = 1;
  1417.     return OK;
  1418. }
  1419.  
  1420. /*
  1421.  * Ack a ZFIN packet, let byegones be byegones
  1422.  */
  1423. void ackbibi()
  1424. {
  1425.     register int n;
  1426.  
  1427.     vfile("ackbibi:");
  1428.     Readnum = 1;
  1429.     stohdr(0L);
  1430.     for (n=3; --n>=0; )
  1431.     {
  1432.         PURGELINE;
  1433.         zshhdr(4, ZFIN, Txhdr);
  1434.         switch (readline(100))
  1435.         {
  1436.           case 'O':
  1437.         readline(1);    /* Discard 2nd 'O' */
  1438.         return;
  1439.           case RCDO:
  1440.         return;
  1441.           case TIMEOUT:
  1442.           default:
  1443.         break;
  1444.         }
  1445.     }
  1446. }
  1447.  
  1448.  
  1449. /*
  1450.  * Strip leading ! if present, do shell escape. 
  1451.  */
  1452. int sys2(s)
  1453. register char *s;
  1454. {
  1455.     if (*s == '!')
  1456.         ++s;
  1457.     return stsystem(s);
  1458. }
  1459. /*
  1460.  * Strip leading ! if present, do exec.
  1461.  */
  1462. void exec2(s)
  1463. char *s;
  1464. {
  1465. /** Are you kidding
  1466.     if (*s == '!')
  1467.         ++s;
  1468.     mode(0);
  1469.     execl("/bin/sh", "sh", "-c", s); 
  1470. **/
  1471. }
  1472.  
  1473. /*
  1474.  * Touch a file
  1475.  */
  1476. #ifndef MANX
  1477. #ifndef __GNUC__
  1478. #undef Fdatime        /* There exist brain damaged versions of osbind.h */
  1479. #define    Fdatime(a,b,c)    gemdos(0x57,a,b,c)
  1480. #endif /* __GNUC__ */
  1481. #endif /* MANX has its _Gemdos stuff */
  1482.  
  1483. void touch(name, timep)
  1484. char *name;
  1485. unsigned int *timep;
  1486. {
  1487.     register int handl;
  1488.  
  1489.     if((handl = Fopen(name, 0)) < 0)
  1490.     {
  1491. #ifndef REMOTE
  1492.         fprintf(STDERR,"*WARNING* Could not set file modification time for %s\n",
  1493.             name);
  1494. #endif
  1495.         return;
  1496.     }
  1497.  
  1498.  
  1499.     Fdatime(timep, handl, 1);
  1500.     Fclose(handl);
  1501. }
  1502.  
  1503. /* -eof- */
  1504.